package br.ufc.histogram;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;

import net.sf.jsqlparser.JSQLParserException;
import br.ufc.parser.Query;
import br.ufc.util.ReverseLineInputStream;

public class Histogram {

	private String attribute;
	private float interval;
	private float globalMinBound;
	private float globalMaxbound;
	private File file;
	private ArrayList<Float> values;
	private HistogramPosition[] histogram;
	
	public Histogram(String attribute, String fileName) throws FileNotFoundException{
		this.attribute = attribute;
		this.interval = 100;
		this.globalMinBound = Float.MAX_VALUE;
		this.globalMaxbound = Float.MIN_VALUE;
		this.file = new File(fileName);
		this.values = new ArrayList<Float>();
	}
	
    public void loadQueries() throws IOException, JSQLParserException{
    	
    	BufferedReader in = new BufferedReader (new InputStreamReader (new ReverseLineInputStream(this.file)));
    	String cvsSplitBy = ";;";
    	
    	while(true) {
    	    String line = in.readLine();
    	    
    	    if (line == null) {
    	        break;
    	    }
    	    
    	    String[] lineCSV = line.split(cvsSplitBy);
			String query = lineCSV[4];

			Query q = new Query(query);
//			HashMap<String, String> restrictions = q.getRestrictions();
			HashMap<String, String> restrictions = null;
			
			if (restrictions.containsKey(this.attribute)) {
				String s = restrictions.get(this.attribute);
				s = s.substring(1, s.length()-1);
				float f = Float.parseFloat(s);
				this.values.add(f);
			}
    	}    	
    	in.close();
    }
	
	public void getBounds(){
		//Sort the elements in ascendent order
		Collections.sort(values);
		
		//Get the maximum and the minimum values of the attribute
		this.globalMinBound = values.get(0);
		this.globalMaxbound = values.get(values.size() - 1);
		
		//Instantiate the array, calculating the number of positions according to the interval size
		histogram = new HistogramPosition[Math.round((this.globalMaxbound - this.globalMinBound)/this.interval)];
		
		//Set the count 0 for every position of the histogram
		float min = this.globalMinBound;
		for (int i = 0; i < histogram.length; i++) {
			histogram[i] = new HistogramPosition(0, min, min + interval);			
			min = min + interval;
		}
	}
	
	public void build() throws IOException, JSQLParserException{
		float start = 0;
		int index = 0;
		
		this.loadQueries();
		this.getBounds();
		
		start = this.globalMinBound;
		
		for (Float value : values) {
			if (value <= start + interval) {
				histogram[index].increaseCount();
			} else {
				index++;
				start = start + interval;
			}
		}
	}
	
	public void sort() {
		Arrays.sort(histogram);
	}
	
	public void printHistogram(){
		for (int i = 0; i < this.histogram.length; i++) {
			System.out.println("["+i+"]: " + "[" + this.histogram[i].getMinBound() + ", " + this.histogram[i].getMaxBound()+ "] " + this.histogram[i].getCount());
		}
	}
	
	public String schedule(String sql) throws JSQLParserException {
		
		Query q = new Query(sql);
//		HashMap<String, String> restrictions = q.getRestrictions();
		HashMap<String, String> restrictions = null;
		
		if (restrictions.containsKey(this.attribute)) {
			String s = restrictions.get(this.attribute);
			s = s.substring(1, s.length() - 1);
			float f = Float.parseFloat(s);
			
			for (int i = 0; i < histogram.length; i++) {
				if (histogram[i].getMinBound() < f && f < histogram[i].getMaxBound()) {
					return histogram[i].getVm();
				}
			}
		}
		
		return histogram[0].getVm();
	}
	
	public HistogramPosition[] getHistogram() {
		return histogram;
	}

	public void setHistogram(HistogramPosition[] histogram) {
		this.histogram = histogram;
	}
}
